package pl.mchaniewski.ryneczek.web.user;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.primefaces.model.chart.PieChartModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;

import pl.mchaniewski.ryneczek.pojo.Company;
import pl.mchaniewski.ryneczek.pojo.Order;
import pl.mchaniewski.ryneczek.pojo.Portfolio;
import pl.mchaniewski.ryneczek.pojo.Quotation;
import pl.mchaniewski.ryneczek.services.OrderService;
import pl.mchaniewski.ryneczek.services.PortfolioService;
import pl.mchaniewski.ryneczek.services.QuotationService;
import pl.mchaniewski.ryneczek.utilities.DateUtil;
import pl.mchaniewski.ryneczek.utilities.I18nUtil;

@Component
@Scope("session")
@PreAuthorize("isAuthenticated()")
public class SelectedPortfolioBean {
    private static final Logger logger = LoggerFactory
            .getLogger(SelectedPortfolioBean.class);
    private PortfolioService portfolioService;
    private OrderService orderService;
    private QuotationService quotationService;
    private Integer selectedPortfolioId;
    private PieChartModel pieChartModel;

    private static final int MAX_COMPANIES_ON_GRAPH = 9;

    @Autowired
    public void setPortfolioService(PortfolioService portfolioService) {
        this.portfolioService = portfolioService;
    }

    @Autowired
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }

    @Autowired
    public void setQuotationService(QuotationService quotationService) {
        this.quotationService = quotationService;
    }

    public Integer getSelectedPortfolioId() {
        return selectedPortfolioId;
    }

    public Portfolio getSelectedPortfolio() {
        return (getSelectedPortfolioId() != null) ? portfolioService
                .findById(getSelectedPortfolioId()) : null;
    }

    public void setSelectedPortfolioId(Integer selectedPortfolioId) {
        this.selectedPortfolioId = selectedPortfolioId;
    }

    public PieChartModel getPieChartModel() {
        if (logger.isDebugEnabled()) {
            logger.debug("Chart is being drawn.");
        }

        Map<String, BigDecimal> portfolioStockValues = portfolioService
                .getPortfolioActiveStockValues(getSelectedPortfolioId());

        pieChartModel = new PieChartModel();

        if (portfolioStockValues != null) {
            if (portfolioStockValues.size() > MAX_COMPANIES_ON_GRAPH) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Before sorting.");
                }

                List<Map.Entry<String, BigDecimal>> entries = new ArrayList<Map.Entry<String, BigDecimal>>(
                        portfolioStockValues.entrySet());
                Collections.sort(entries,
                        new Comparator<Map.Entry<String, BigDecimal>>() {
                            @Override
                            public int compare(Map.Entry<String, BigDecimal> a,
                                    Map.Entry<String, BigDecimal> b) {
                                int compare = a.getValue().compareTo(
                                        b.getValue());
                                return compare != 0 ? compare : 1;
                            }
                        });

                BigDecimal rest = BigDecimal.ZERO;
                for (int i = 0; i < entries.size(); ++i) {
                    if (i < (entries.size() - MAX_COMPANIES_ON_GRAPH)) {
                        rest = rest.add(entries.get(i).getValue());
                    } else {
                        pieChartModel.set(entries.get(i).getKey(),
                                entries.get(i).getValue());
                    }
                }
                pieChartModel.set(I18nUtil
                        .getLocalizedMessage("selectedportfoliobean.rest"),
                        rest);

                if (logger.isDebugEnabled()) {
                    logger.debug("After sorting.");
                }
            } else {
                for (Map.Entry<String, BigDecimal> entry : portfolioStockValues
                        .entrySet()) {
                    pieChartModel.set(entry.getKey(), entry.getValue());
                }
            }
        }

        pieChartModel.set(I18nUtil
                .getLocalizedMessage("selectedportfoliobean.cash"),
                portfolioService
                        .getPortfolioRealBalance(getSelectedPortfolioId()));

        return pieChartModel;
    }

    public String getBalance() {
        return getDecimalBalance() != null ? getDecimalBalance().toString()
                : null;
    }

    public String getOriginalBalance() {
        return getSelectedPortfolio().getOriginalBalance().toString();
    }

    public String getBlockedBalance() {
        return portfolioService.getPortfolioBlockedBalance(
                getSelectedPortfolioId()).toString();
    }

    public String getPortfolioValue() {
        return getPortfolioDecimalValue() != null ? getPortfolioDecimalValue()
                .toString() : null;
    }

    public String getPortfolioTotalValue() {
        BigDecimal portf = getPortfolioDecimalValue();
        BigDecimal bala = getDecimalBalance();
        if (portf != null && bala != null) {
            return portf.add(bala).toString();
        }

        return null;
    }

    public String getCommissionValue() {
        return getSelectedPortfolio().getTotalCommissions().toString();
    }

    public Integer getNumberOfCompanies() {
        List<Company> companies = portfolioService.getPortfolioCompanies(
                getSelectedPortfolioId(), true);

        return (companies != null) ? companies.size() : null;
    }

    public Integer getNumberOfActiveOrders() {
        List<Order> orders = orderService.findByPortfolioIdAndStatus(
                getSelectedPortfolioId(), Order.STATUS_ACCEPTED);
        return (orders != null) ? orders.size() : null;
    }

    public Integer getNumberOfCompletedOrders() {
        List<Order> orders = orderService.findByPortfolioIdAndStatus(
                getSelectedPortfolioId(), Order.STATUS_COMPLETED);
        return (orders != null) ? orders.size() : null;
    }

    public Integer getNumberOfCanceledOrders() {
        List<Order> orders = orderService.findByPortfolioIdAndStatus(
                getSelectedPortfolioId(), Order.STATUS_CANCELED);
        return (orders != null) ? orders.size() : null;
    }

    public String getCreatedAt() {
        return DateUtil.dateToString(getSelectedPortfolio().getCreateDate());
    }

    public List<Quotation> getPortfolioCompanies() {
        List<Company> companies = portfolioService.getPortfolioCompanies(
                getSelectedPortfolioId(), true);

        List<Quotation> quotationList = new LinkedList<Quotation>();
        if (companies != null) {
            for (Company c : companies) {
                Quotation latest = quotationService.findLatest(
                        c.getCompanyid(), true);

                if (latest != null) {
                    quotationList.add(latest);
                }
            }
        }

        return quotationList;
    }

    private BigDecimal getDecimalBalance() {
        return portfolioService
                .getPortfolioRealBalance(getSelectedPortfolioId());
    }

    private BigDecimal getPortfolioDecimalValue() {
        Map<String, BigDecimal> portfolioStockValues = portfolioService
                .getPortfolioActiveStockValues(getSelectedPortfolioId());

        BigDecimal value = BigDecimal.ZERO;
        if (portfolioStockValues != null) {
            for (Map.Entry<String, BigDecimal> entry : portfolioStockValues
                    .entrySet()) {
                value = value.add(entry.getValue());
            }
        }

        return value;
    }
}
